﻿Imports System.Threading
Imports System.Xml.Serialization
Imports System.IO

Public Class SessionEngine

    Private Shared _instance As SessionEngine

    Sub New()
    End Sub

    Public Shared ReadOnly Property getInstance() As SessionEngine
        Get
            ' if not exists..  create 
            If _instance Is Nothing Then
                _instance = New SessionEngine()

                ' try load from disk
                _instance.tryLoad()
            End If

            Return _instance
        End Get
    End Property

    ''-------------------------------------------------------------------------------------
    ''----------------------------------- PUBLIC METHODS  ---------------------------------
    ''-------------------------------------------------------------------------------------
    Private oSessions As Generic.Dictionary(Of String, ItemSession)
    Private oMutex As New Mutex

    ''' <summary>
    ''' Session dictionary
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property sessions() As Generic.Dictionary(Of String, ItemSession)
        Get
            Return oSessions
        End Get
        Set(ByVal value As Generic.Dictionary(Of String, ItemSession))
            oSessions = value
        End Set
    End Property

    ''' <summary>
    ''' Return true if exists one session
    ''' </summary>
    ''' <param name="token"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function existsSession(token As String) As Boolean
        If oSessions IsNot Nothing AndAlso token IsNot Nothing Then
            Return oSessions.ContainsKey(token)
        End If
        Return False
    End Function

    ''' <summary>
    ''' Return ItemSession for token
    ''' </summary>
    ''' <param name="token"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function getSessionByToken(token As String) As ItemSession
        If oSessions IsNot Nothing Then
            Return oSessions(token)
        End If
        Return Nothing
    End Function


    ''' <summary>
    ''' Return list of my ItemSession 
    ''' </summary>
    ''' <param name="token">token</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function getAllMySessions(token As String) As Generic.List(Of ItemSession)
        Dim res As New Generic.List(Of ItemSession)

        Dim current As ItemSession = getSessionByToken(token)

        For Each key As String In oSessions.Keys
            If oSessions(key).userId = current.userId Then
                res.Add(oSessions(key))
            End If
        Next
        Return res
    End Function

    ''' <summary>
    ''' Return true if exists sessions
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function haveSessions() As Boolean
        Return oSessions IsNot Nothing AndAlso oSessions.Count() > 0
    End Function

    ''' <summary>
    ''' Create an .net session without ade reference
    ''' </summary>
    ''' <param name="clientSession">ClientSessionVO</param>
    ''' <remarks></remarks>
    Public Sub createSession(clientSession As Models.Security.ClientSessionVO)
        Dim item As New ItemSession(clientSession)
        addItemToSession(item)
    End Sub

    ''' <summary>
    ''' Update lastUpdate property in the session
    ''' </summary>
    ''' <param name="token"></param>
    ''' <remarks></remarks>
    Public Sub markAsInUse(token As String)
        If existsSession(token) Then
            getSessionByToken(token).lastUpdate = Now
        End If
    End Sub


    ''' <summary>
    ''' Check for permission in a sessions by token 
    ''' </summary>
    ''' <param name="token"></param>
    ''' <param name="process"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function hasAccess(token As String, process As String) As Boolean
        If existsSession(token) Then
            Try
                If getSessionByToken(token).clientSession.userLogin = "super" Then
                    Return True
                Else
                    Return getSessionByToken(token).clientSession.process.Contains(process)
                End If
            Catch ex As Exception
            End Try
        End If
        Return False
    End Function


    ''' <summary>
    ''' Depure all sessions, kill session timeouted
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub purgeSessions()
        If oSessions IsNot Nothing Then
            Dim tokensToKill As New Generic.List(Of String)
            For Each token As String In oSessions.Keys
                Dim minutes As Long = DateDiff(DateInterval.Minute, oSessions(token).lastUpdate, Now)
                If minutes > oSessions(token).timeout Then
                    tokensToKill.Add(token)
                End If
            Next

            '' kill the sessions
            For Each token As String In tokensToKill
                killSessionByToken(token)
            Next
        End If
    End Sub

    ''' <summary>
    ''' Kill session by token
    ''' </summary>
    ''' <param name="token"></param>
    ''' <remarks></remarks>
    Public Sub killSessionByToken(token As String)
        If existsSession(token) Then

            'Call calcEngine to kill ADE
            'Dim engine As New CalcLib.CalcEngine()
            'engine.freeResources(token)

            oSessions.Remove(token)
        End If
    End Sub

    ''' <summary>
    ''' Save the current session list to DISK
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub persist()
        oMutex.WaitOne()

        ' DISK METHOD

        Dim filename As String = System.Configuration.ConfigurationManager.AppSettings("dataPath") & "mainApp.data"
        Dim cData As String = ""
        If haveSessions() Then
            Dim oList As New Generic.List(Of ItemSession)
            For Each key As String In oSessions.Keys
                oList.Add(oSessions(key))
            Next
            Dim serializer As New XmlSerializer(GetType(ItemSession()))
            Dim writer As New StringWriter()
            serializer.Serialize(writer, oList.ToArray)
            cData = writer.ToString()

        End If
        My.Computer.FileSystem.WriteAllText(filename, cData, False)

        oMutex.ReleaseMutex()

    End Sub

    ''' <summary>
    ''' Try to load session list from DISK
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub tryLoad()

        ' DISK METHOD
        Dim filename As String = System.Configuration.ConfigurationManager.AppSettings("dataPath") & "mainApp.data"
        If IO.File.Exists(filename) Then

            Dim cData As String = My.Computer.FileSystem.ReadAllText(filename)
            Dim serializer As New XmlSerializer(GetType(ItemSession()))
            Dim oReader As New IO.StringReader(cData)

            Try
                Dim oList As ItemSession() = serializer.Deserialize(oReader)
                If oList IsNot Nothing AndAlso oList.Count > 0 Then
                    For Each oItem As ItemSession In oList
                        addItemToSession(oItem)
                    Next
                End If
            Catch ex As Exception
                oReader.Close()
            End Try

        End If

    End Sub

    ''' <summary>
    ''' Add item session to dictionary
    ''' </summary>
    ''' <param name="item"></param>
    ''' <remarks></remarks>
    Private Sub addItemToSession(item As ItemSession)

        If oSessions Is Nothing Then
            oSessions = New Generic.Dictionary(Of String, ItemSession)
        End If

        If Not oSessions.Keys.Contains(item.token) Then
            oSessions(item.token) = item
        End If

    End Sub

End Class